
package com.netty;


import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.springframework.stereotype.Component;

import java.util.List;


/**
 * 解码器
 */
@Component
public class ServerDecoder extends ByteToMessageDecoder {


    private int lengthFieldOffset;
    private int lengthFieldEndOffset;
    private int lengthAdjustment;
    private int initialBytesToStrip;


    /**
     * @param lengthFieldOffset   偏移位置
     * @param lengthFieldLength   数据包长度
     * @param initialBytesToStrip 等价数据包长度
     */
    public ServerDecoder(int lengthFieldOffset, int lengthFieldLength,
                         int lengthAdjustment, int initialBytesToStrip) {
        this.lengthFieldOffset = lengthFieldOffset;
        this.lengthAdjustment = lengthAdjustment;
        lengthFieldEndOffset = lengthFieldOffset + lengthFieldLength;
        this.initialBytesToStrip = initialBytesToStrip;
    }


    /**
     * 4+length
     * 包长(4字节)+msgID(4字节)+conetent(length)
     * lengthFieldOffset   = 0
     * lengthFieldLength   = 4
     * lengthAdjustment    = 0
     * initialBytesToStrip = 4
     *
     * @param ctx
     * @param in
     * @param out
     * @throws Exception
     */
    @Override
    protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        // not enougth
        if (in.readableBytes() < lengthFieldEndOffset) {
            return;
        }
        int actualLengthFieldOffset = in.readerIndex() + lengthFieldOffset;

        //get frame length
        long frameLength = in.getUnsignedInt(actualLengthFieldOffset);

        frameLength += lengthAdjustment + lengthFieldEndOffset;

        // never overflows because it's less than maxFrameLength
        int frameLengthInt = (int) frameLength;
        if (in.readableBytes() < frameLengthInt) {
            return;
        }
        // extract frame
        int readerIndex = in.readerIndex() + initialBytesToStrip;//
        int actualFrameLength = frameLengthInt - initialBytesToStrip; //数据长度

        //heap  byte array  and  copy data to array
        byte[] frame = new byte[actualFrameLength];
        in.getBytes(readerIndex, frame);//msgID+fbdata

        //Sets the {@code readerIndex} of this buffer.
        //make expandCumulation work well
        in.readerIndex(readerIndex + actualFrameLength);

        //decode message and add to list to cache ，this is byteBuffer
        //forEach dispatcher     frame (byte[] or ByteBuffer)
        out.add(frame);
    }

}
